package org.uoss.webapp.framework.json;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.util.CycleDetectionStrategy;

import org.apache.struts2.dispatcher.StrutsResultSupport;
import org.uoss.core.util.ValidationUtil;
import org.uoss.webapp.framework.http.HttpUtil;
import org.uoss.webapp.framework.json.support.IgnoreFieldProcessorImpl;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;

public final class JSONObjectResult<T> extends StrutsResultSupport implements Result {

	private static final long serialVersionUID = -99305304784888228L;
	static JSONDateProcessor jsonDateProcessor = new JSONDateProcessor();
	static JSONPersistentSetProcessor jsonSetProcessor = new JSONPersistentSetProcessor();
	private List<Pattern> includeProperties;
	private List<Pattern> excludeProperties;
	
	protected void doExecute(String location, ActionInvocation invocation) throws Exception {
		if (invocation == null || invocation.getStack() == null) {
			return;
		}
		String[] requiredProperties = null;//this.getProperties(this.getIncludeProperties());
		if (ValidationUtil.isEmpty(requiredProperties)) {
			return;
		}
		HttpServletResponse response = HttpUtil.getHttpServletResponse();
		response.setContentType("text/javascript;charset=utf-8");
		JsonConfig config = this.getJsonConfig();
		for (String requiredProperty : requiredProperties) {
			if (ValidationUtil.isEmpty(requiredProperty)) {
				continue;
			}
			this.writeJsonObject(invocation.getStack().findValue(requiredProperty), config, response);
		}
	}

	private void writeJsonObject(Object obj, JsonConfig jsonConfig, HttpServletResponse response) {
		if (ValidationUtil.isEmpty(obj)) {
			return;
		}
		PrintWriter out = null;
		try {
			out = response.getWriter();
			if (obj instanceof Collection<?>) {
				out.write(JSONArray.fromObject(obj, jsonConfig).toString());
			} 
			else {
				out.write(JSONObject.fromObject(obj, jsonConfig).toString());
			}
		}
		catch (IOException e) {
			e.printStackTrace();
		} 
		finally {
			if (out != null) {
				out.flush();
				out.close();
			}
		}
	}

	private JsonConfig getJsonConfig() {
		JsonConfig config = new JsonConfig();
		config.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
		config.registerJsonValueProcessor(Date.class, jsonDateProcessor);
		String[] fields = null;//this.getProperties(this.getExcludeProperties());
		config.setJsonPropertyFilter(new IgnoreFieldProcessorImpl(fields));
		return config;
	}

	private String[] getProperties(String properties) {
		String[] fields = null;
		if (properties == null) {
			return fields;
		}
		if (-1 != properties.indexOf(",")) {
			fields = properties.split(",");
		} else {
			fields = new String[] { properties };
		}
		return fields;
	}

	public List<Pattern> getIncludeProperties() {
		return includeProperties;
	}

	public void setIncludeProperties(List<Pattern> includeProperties) {
		this.includeProperties = includeProperties;
	}

	public List<Pattern> getExcludeProperties() {
		return excludeProperties;
	}

	public void setExcludeProperties(List<Pattern> excludeProperties) {
//	    List excludePatterns = JSONUtil.asList(commaDelim);
//	    if (excludePatterns != null) {
//	      this.excludeProperties = new ArrayList(excludePatterns.size());
//	      for (String pattern : excludePatterns)
//	        this.excludeProperties.add(Pattern.compile(pattern));
	}
}
